﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{
    /// <summary>
    /// 长方体
    /// </summary>
    public class Cuboid3d : Solid3d
    {
        private double width;
        private double height;
        private double depth;

        public double Width { get => width; set => SetSize(value, height, depth); }
        public double Height { get => height; set => SetSize(width, value, depth); }
        public double Depth { get => depth; set => SetSize(width, height, value); }
        public Cuboid3d() { }
        public Cuboid3d(double width, double height, double depth)
        {
            this.SetSize(width, height, depth);
        }
        public Surface3d[] Surfaces;
        private TopoFaceModel topoFaceModel;
        public Cuboid3d SetSize(double width, double height, double depth)
        {
            if (topoFaceModel != null && (this.width != width || this.height != height || this.depth != depth))
            {
                topoFaceModel = null;
            }
            this.width = width;
            this.height = height;
            this.depth = depth;
            return this;
        }

        private Vector3 lbf;
        private Vector3 rbf;
        private Vector3 rbb;
        private Vector3 lbb;
        private Vector3 ltf;
        private Vector3 rtf;
        private Vector3 rtb;
        private Vector3 ltb;

        public override TopoFaceModel CreateTopoModel()
        {
            if (topoFaceModel != null)
                return topoFaceModel;

            var halfW = width / 2;
            var halfH = height / 2;
            var halfD = depth / 2;
            lbf = new Vector3(-halfW, -halfH, -halfD);
            rbf = new Vector3(halfW, -halfH, -halfD);
            rbb = new Vector3(halfW, halfH, -halfD);
            lbb = new Vector3(-halfW, halfH, -halfD);
            ltf = new Vector3(-halfW, -halfH, halfD);
            rtf = new Vector3(halfW, -halfH, halfD);
            rtb = new Vector3(halfW, halfH, halfD);
            ltb = new Vector3(-halfW, halfH, halfD);
            var front = new PlanarSurface3d(new Plane(new Vector3(0, -1, 0), -halfH)
                , new List<Curve3d> { new Line3d(lbf, rbf), new Line3d(rbf, rtf), new Line3d(rtf, ltf), new Line3d(ltf, lbf) });

            var back = new PlanarSurface3d(new Plane(new Vector3(0, 1, 0), -halfH)
          , new List<Curve3d> { new Line3d(rbb, lbb), new Line3d(lbb, ltb), new Line3d(ltb, rtb), new Line3d(rtb, rbb) });

            var left = new PlanarSurface3d(new Plane(new Vector3(-1, 0, 0), -halfW)
                , new List<Curve3d> { new Line3d(lbb, lbf), new Line3d(lbf, ltf), new Line3d(ltf, ltb), new Line3d(ltb, lbb) });

            var right = new PlanarSurface3d(new Plane(new Vector3(1, 0, 0), -halfW)
                , new List<Curve3d> { new Line3d(rbf, rbb), new Line3d(rbb, rtb), new Line3d(rtb, rtf), new Line3d(rtf, rbf) });

            var top = new PlanarSurface3d(new Plane(new Vector3(0, 0, 1), -halfD)
               , new List<Curve3d> { new Line3d(ltf, rtf), new Line3d(rtf, rtb), new Line3d(rtb, ltb), new Line3d(ltb, ltf) });

            var bottom = new PlanarSurface3d(new Plane(new Vector3(0, 0, -1), -halfD)
               , new List<Curve3d> { new Line3d(lbb, rbb), new Line3d(rbb, rbf), new Line3d(rbf, lbf), new Line3d(lbf, lbb) });
            this.Surfaces = new Surface3d[6] { front, back, left, right, top, bottom };
            this.topoFaceModel = new TopoFaceModel() { Surfaces = this.Surfaces.ToListEx() };
            return this.topoFaceModel;
        }

        public override Solid3d CreateMesh()
        {
            base.CreateMesh();
            var idxsCount = this.Geometry.Indics.Length;
            this.Geometry.Groups = new GeometryGroup[6]
            {
                new GeometryGroup{Name="Front", Start=0,Count=idxsCount/6,MaterialIndex=0 },
                new GeometryGroup{Name="Back", Start=idxsCount*1/6,Count=idxsCount/6,MaterialIndex=1 },
                new GeometryGroup{Name="Left", Start=idxsCount*2/6,Count=idxsCount/6,MaterialIndex=2 },
                new GeometryGroup{Name="Right", Start=idxsCount*3/6,Count=idxsCount/6,MaterialIndex=3 },
                new GeometryGroup{Name="Top", Start=idxsCount*4/6,Count=idxsCount/6,MaterialIndex=4 },
                new GeometryGroup{Name="Bottom", Start=idxsCount*5/6,Count=idxsCount/6,MaterialIndex=5 },
            };
            this.Edge = new GeometryData();
            var v3Array = new double[3 * 8];
            lbf.ToArray(v3Array, 0);
            rbf.ToArray(v3Array, 3);
            rbb.ToArray(v3Array, 6);
            lbb.ToArray(v3Array, 9);
            ltf.ToArray(v3Array, 12);
            rtf.ToArray(v3Array, 15);
            rtb.ToArray(v3Array, 18);
            ltb.ToArray(v3Array, 21);
            var idxArray = new ListEx<int>();
            idxArray.Push(0, 1, 1, 2, 2, 3, 3, 0,
                          4, 5, 5, 6, 6, 7, 7, 4,
                          0, 4, 1, 5, 2, 6, 3, 7);
            this.Edge.Verteics = v3Array;
            this.Edge.Indics = idxArray.ToArray();
            return this;
        }
    }
}